﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace LongNet.Threading
{
    /// <summary>
    /// Disposable acts as a base class for deriving a disposable class. 
    /// Represents an implementation of the IDisposable interface.
    /// </summary>
    /// <remarks>
    /// Override Dispose(disposing) in derived classes. When this method is called, always 
    /// release unmanaged resources, and dispose of managed resources only if the 
    /// disposing parameter is true.
    /// </remarks>
    public abstract class Disposable : IDisposable
    {
        #region Fileds

        // A value which indicates the dispose state. 0 indicates undisposed, 1 indicates disposing
        // or disposed.
        private int disposeState;

        #endregion

        #region Properties

        /// <summary>
        /// Gets a value indicating whether the object is disposed.
        /// </summary>
        public bool IsDisposed
        {
            get
            {
                return Thread.VolatileRead(ref this.disposeState) == 1;
            }
        }

        #endregion

        #region Destructor

        /// <summary>
        /// Finalizes current instance.
        /// </summary>
        ~Disposable()
        {
            // The destructor has been called as a result of finalization, indicating that the object
            // was not disposed of using the Dispose() method. In this case, call the Dispose(disposing)
            // method with the disposing flag set to false, indicating that derived classes
            // may only release unmanaged resources.
            this.Dispose(false);
        }

        #endregion

        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with disposing of resources.
        /// </summary>
        public void Dispose()
        {
            // Attempt to move the dispose state from 0 to 1. If successful, we can be assured that
            // this thread is the first thread to do so, and can safely dispose of the object.
            if (Interlocked.CompareExchange(ref this.disposeState, 1, 0) == 0)
            {
                // Call the Dispose(disposing) method with the disposing flag set to true, indicating
                // that derived classes may release unmanaged resources and dispose of managed resources.
                this.Dispose(true);

                // Suppress finalization of this object (remove it from the finalization queue and
                // prevent the destructor from being called).
                GC.SuppressFinalize(this);
            }
        }

        void IDisposable.Dispose()
        {
            this.Dispose();
        }

        #endregion

        #region Abstract Members

        /// <summary>
        /// Dispose resources. Override this method in derived classes. Unmanaged resources should always be released
        /// when this method is called. Managed resources may only be disposed of if disposing is true.
        /// </summary>
        /// <param name="disposing">A value which indicates whether managed resources may be disposed of.</param>
        protected abstract void Dispose(bool disposing);

        #endregion
    }
}
